﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Zj.OpenAuth.Domain.Core;
using Zj.OpenAuth.Domain.Interface;

namespace Zj.OpenAuth.Repository
{
    /// <summary>
    /// base repository class
    /// </summary>
    public class BaseRepository<T> : IRepository<T>
          where T : BaseEntity, new()
    {
        #region Identity
        protected DbContext Context { get; private set; }

        public BaseRepository(DbContext context)
        {
            this.Context = context;
        }
        #endregion Identity

        public T Get(int id)
        {
            return this.Context.Set<T>().FirstOrDefault(e => e.Id == id);
        }

        public T Insert(T t)
        {
            this.Context.Set<T>().Add(t);
            this.Commit();
            return t;
        }

        public IEnumerable<T> Insert(IEnumerable<T> tList)
        {
            this.Context.Set<T>().AddRange(tList);
            this.Commit();//一个链接  多个sql
            return tList;
        }

        #region Query
        public T Find(int id)
        {
            return this.Context.Set<T>().Find(id);
        }

        public IQueryable<T> Set()
        {
            return this.Context.Set<T>();
        }

        public IQueryable<T> Query(Expression<Func<T, bool>> funcWhere)
        {
            return this.Context.Set<T>().Where<T>(funcWhere);
        }

        public IQueryable<T> QueryPage<S>(Expression<Func<T, bool>> funcWhere, int pageSize, int pageIndex, out int rowCount, Expression<Func<T, S>> funcOrderby, bool isAsc = true)
        {
            var list = this.Set();
            if (funcWhere != null)
            {
                list = list.Where<T>(funcWhere);
            }
            if (isAsc)
            {
                list = list.OrderBy(funcOrderby);
            }
            else
            {
                list = list.OrderByDescending(funcOrderby);
            }
            rowCount = this.Context.Set<T>().Count(funcWhere);
            return list.Skip((pageIndex - 1) * pageSize).Take(pageSize);
        }
        #endregion

        public T Update(T t)
        {
            if (t == null) throw new Exception("t is null");

            this.Context.Set<T>().Attach(t);//将数据附加到上下文，支持实体修改和新实体，重置为UnChanged
            this.Context.Entry<T>(t).State = EntityState.Modified;
            this.Commit();//保存 然后重置为UnChanged
            return t;
        }
        /*
         public enum EntityState
    {
        // 摘要:
        //     对象存在，但未由对象服务跟踪。在创建实体之后、但将其添加到对象上下文之前，该实体处于此状态。通过调用 System.Data.Objects.ObjectContext.Detach(System.Object)
        //     方法从上下文中移除实体后，或者使用 System.Data.Objects.MergeOption.NoTrackingSystem.Data.Objects.MergeOption
        //     加载实体后，该实体也会处于此状态。
        Detached = 1,
        //
        // 摘要:
        //     自对象加载到上下文中后，或自上次调用 System.Data.Objects.ObjectContext.SaveChanges() 方法后，此对象尚未经过修改。
        Unchanged = 2,
        //
        // 摘要:
        //     对象已添加到对象上下文，但尚未调用 System.Data.Objects.ObjectContext.SaveChanges() 方法。对象是通过调用
        //     System.Data.Objects.ObjectContext.AddObject(System.String,System.Object)
        //     方法添加到对象上下文中的。
        Added = 4,
        //
        // 摘要:
        //     使用 System.Data.Objects.ObjectContext.DeleteObject(System.Object) 方法从对象上下文中删除了对象。
        Deleted = 8,
        //
        // 摘要:
        //     对象已更改，但尚未调用 System.Data.Objects.ObjectContext.SaveChanges() 方法。
        Modified = 16,
    }
         */

        public void Update(IEnumerable<T> tList) 
        {
            foreach (var t in tList)
            {
                this.Context.Set<T>().Attach(t);
                this.Context.Entry<T>(t).State = EntityState.Modified;
            }
            this.Commit();
        }


        public T InsertOrUpdate(T entity)
        {
            if (Get(entity.Id) != null)
                return Update(entity);
            return Insert(entity);
        }

        public void Delete(T t) 
        {
            if (t == null) throw new Exception("t is null");
            this.Context.Set<T>().Remove(t);
            this.Commit();
        }

        public void Delete(int Id)
        {
            T t = this.Find(Id);
            if (t == null) throw new Exception("t is null");
            this.Context.Set<T>().Remove(t);
            this.Commit();
        }

        public void Delete(IEnumerable<T> tList)
        {
            foreach (var t in tList)
            {
                this.Context.Set<T>().Attach(t);
            }
            this.Context.Set<T>().RemoveRange(tList);
            this.Commit();
        }


        public void Commit()
        {
            this.Context.SaveChanges();
        }

        public IQueryable<T> ExcuteQuery(string sql, SqlParameter[] parameters)
        {
            return this.Context.Database.SqlQuery<T>(sql, parameters).AsQueryable();
        }

        public void Excute(string sql, SqlParameter[] parameters) 
        {
            DbContextTransaction trans = null;
            try
            {
                trans = this.Context.Database.BeginTransaction();
                this.Context.Database.ExecuteSqlCommand(sql, parameters);
                trans.Commit();
            }
            catch (Exception ex)
            {
                if (trans != null)
                    trans.Rollback();
                throw ex;
            }
        }

        public virtual void Dispose()
        {
            if (this.Context != null)
            {
                this.Context.Dispose();
            }
        }

        public bool IsExist(Expression<Func<T, bool>> funcWhere) 
        {
            return this.Context.Set<T>().Count<T>(funcWhere) > 0;
        }

    }
}
